/******************************************************************************
 * * contact_add.c - implementation of contact add functions
 *
 * *(C) Copyright 2019 Asr International Ltd.
 * * All Rights Reserved
 * ******************************************************************************/
#include "contact_global.h"

/**
 * Update description for Contacts interface if foucs contact changed
 * param (in) Ctrl: VOID *
 * return  VOID
 */
VOID Contacts_Update_Contacts_Interface(VOID)
{
    UI_Normal_Button_Container_Desc_t *Interface =
        (UI_Normal_Button_Container_Desc_t *)Nav_Get_Param(ACT_ID_CONTACTS);
    UI_Button_Desc_t                  *ContBtn;
    lv_ll_t                           *ContactsList;
    Contacts_List_t                   *Contact;
    UINT8                             Len = CONTACTS_MAX_NAME_LENGTH + CONTACTS_MAX_NUMBER_LENGTH + 1;
    UINT16                            Index;
    UINT16                            Count;                                     // contact total number
    UINT8                             i;

    if (NULL == Interface)
    {
        printf("%s: not in contacts\n", __FUNCTION__);
    }

    if (NULL == g_ContactsMng.InterfaceCtrl.FocusContact)
    {
        printf("%s: foucs contact is NULL\n", __FUNCTION__);
        return;
    }

    Interface->Label.TxtId = LV_LANG_TXT_ID_NONE;

    ContactsList = Contacts_Get_Contacts_Operation_List(&Count);
    Contact = _lv_ll_get_head(ContactsList);
    Index = 0;
    while (Contact)
    {
        if (Contact == g_ContactsMng.InterfaceCtrl.FocusContact)
        {
            printf("%s: contact index %d\n", __FUNCTION__, Index);
            break;
        }
        Contact = _lv_ll_get_next(ContactsList, Contact);
        Index++;
    }

    if (UI_MAX_CONT_BTN_NUM > Index)
    {
        Interface->ButtonContainer.Index = Index;

        Contact = _lv_ll_get_head(ContactsList);
        for (i = 0;i < UI_MAX_CONT_BTN_NUM;i++)
        {
            ContBtn = &Interface->ButtonContainer.ContButton[i];
            if (Contact)
            {
                ContBtn->Valid       = TRUE;
                ContBtn->ButtonIndex = i;
                ContBtn->TxtId       = LV_LANG_TXT_ID_NONE;
                ContBtn->BtnTxt      = (INT8 *)Hal_Mem_Alloc(Len);
                ContBtn->SymbolId2   = Contacts_Get_Contact_Memory_Symbol(Contact->ContactInfo->MemoryAndIndex);
                sprintf(ContBtn->BtnTxt, "%s\n%s", Contact->ContactInfo->Name, Contact->ContactInfo->Number);
                ContBtn->ReleaseFun = Contacts_Btn_Contact_Cb;

                Contact = _lv_ll_get_next(ContactsList, Contact);
            }
            else
            {
                ContBtn->Valid = FALSE;
                if (ContBtn->BtnTxt)
                {
                    Hal_Mem_Free(ContBtn->BtnTxt);
                    ContBtn->BtnTxt = NULL;
                }
            }
        }
        Interface->ButtonContainer.PosY = 0;
    }
    else
    {
        Interface->ButtonContainer.Index = UI_MAX_CONT_BTN_NUM - 1;

        i = UI_MAX_CONT_BTN_NUM;
        while (Contact && (0 < i))
        {
            ContBtn = &Interface->ButtonContainer.ContButton[i - 1];

            ContBtn->Valid       = TRUE;
            ContBtn->ButtonIndex = i - 1;
            ContBtn->TxtId       = LV_LANG_TXT_ID_NONE;
            ContBtn->BtnTxt      = (INT8 *)Hal_Mem_Alloc(Len);
            ContBtn->SymbolId2   = Contacts_Get_Contact_Memory_Symbol(Contact->ContactInfo->MemoryAndIndex);
            sprintf(ContBtn->BtnTxt, "%s\n%s", Contact->ContactInfo->Name, Contact->ContactInfo->Number);
            ContBtn->ReleaseFun = Contacts_Btn_Contact_Cb;

            Contact = _lv_ll_get_prev(ContactsList, Contact);
            i--;
        }
        Interface->ButtonContainer.PosY = (Index + 1 - UI_MAX_CONT_BTN_NUM) * Interface->ButtonContainer.Height;
    }
} /* Contacts_Update_Contacts_Interface */

/**
 * Callback function for additional actions after Creating Contacts_Replace interface
 * param (in) Ctrl: VOID *
 * return  VOID
 */
VOID Contacts_Replace_OnCreate(VOID *Ctrl)
{
    UI_Normal_NoTitle_Desc_t *Interface = (UI_Normal_NoTitle_Desc_t *)Ctrl;
    lv_obj_t                 *Label     = Interface->ContenCont.ContLabel.Label;
    INT8                     *Text;
    UINT8                    Len;
    INT8                     *Output;

    Text   = (INT8 *)(lv_lang_get_text(PHONE_TEXT_ID_REPLACE_Q));
    Len    = strlen(Text) + 2 + CONTACTS_MAX_NAME_LENGTH;
    Output = (INT8 *)Hal_Mem_Alloc(Len);
    sprintf(Output, "%s\n\n%s", Text, g_ContactsMng.InterfaceCtrl.Focus->ContactInfo->Name);
    lv_label_set_text(Label, Output);
    Hal_Mem_Free(Output);
}

/**
 * Callback function for restoring state on Contacts_Replace interface after backward from another activity
 * param (in) Ctrl: VOID *
 * return  VOID
 */
VOID Contacts_Replace_OnRestoreState(VOID *Ctrl)
{
    UI_Normal_NoTitle_Desc_t *Interface = (UI_Normal_NoTitle_Desc_t *)Ctrl;
    lv_obj_t                 *Label     = Interface->ContenCont.ContLabel.Label;
    INT8                     *Text;
    UINT8                    Len;
    INT8                     *Output;

    Text   = (INT8 *)(lv_lang_get_text(PHONE_TEXT_ID_REPLACE_Q));
    Len    = strlen(Text) + 2 + CONTACTS_MAX_NAME_LENGTH;
    Output = (INT8 *)Hal_Mem_Alloc(Len);
    sprintf(Output, "%s\n\n%s", Text, g_ContactsMng.InterfaceCtrl.Focus->ContactInfo->Name);
    lv_label_set_text(Label, Output);
    Hal_Mem_Free(Output);

    g_ContactsMng.InterfaceCtrl.Ctrl        = Ctrl;
    g_ContactsMng.InterfaceCtrl.InterfaceId = ACT_ID_CONTACTS_REPLACE;
}

/**
 * Callback function for handling key pressed on Contacts_Replace interface
 * param (in) Obj: lv_obj_t *
 * param (in) Key_Sta: UI_KEY_STATUS
 * param (in) Key_Val: UI_KEY_VALUE
 * return  UINT8
 */
UINT8 Contacts_Replace_Key_Cb(lv_obj_t *Obj, UI_KEY_STATUS Key_Sta, UI_KEY_VALUE Key_Val)
{
    UINT8                         Len;
    Contacts_Info_t               *ContactInfo;
    UINT32                        Offset;
    NV_UI_Contacts_Contact_Info_t NvContact;
    UINT16                        Index;

    if (KEY_RELEASED == Key_Sta)
    {
        switch (Key_Val)
        {
        case KEY_SOFTRIGHT:
            if (CONTACTS_ACTION_ADD == g_ContactsMng.ContactOper.Action)
            {
                Hal_Mem_Free(g_ContactsMng.InterfaceCtrl.Number);
                g_ContactsMng.InterfaceCtrl.Number = NULL;
            }
            Nav_Back(ACT_ID_ANY);
            break;

        case KEY_END:
            Nav_Home(ACT_ID_ANY);
            break;

        case KEY_OK:
            // replace contact in add contact process, delete original contact then add the new contact
            Len         = strlen(g_ContactsMng.InterfaceCtrl.Number) + 1;
            ContactInfo = g_ContactsMng.InterfaceCtrl.Focus->ContactInfo;
            Contacts_Speed_Dials_Update_Contact(ContactInfo, NULL, g_ContactsMng.InterfaceCtrl.Number);
            Hal_Mem_Set(ContactInfo->Number, 0, CONTACTS_MAX_NUMBER_LENGTH);
            Hal_Mem_Copy(ContactInfo->Number, g_ContactsMng.InterfaceCtrl.Number, Len);

            Index = Contacts_Get_Contact_Index(ContactInfo->MemoryAndIndex);

            if (CONTACTS_MEMORY_PHONE == g_ContactsMng.ContactOper.DestMemory)
            {
                Hal_Mem_Copy(NvContact.Name, ContactInfo->Name, CONTACTS_MAX_NAME_LENGTH);
                Hal_Mem_Copy(NvContact.Number, ContactInfo->Number, CONTACTS_MAX_NUMBER_LENGTH);
                NvContact.ToneIndex = ContactInfo->ToneIndex;
                Len                 = sizeof(NV_UI_Contacts_Contact_Info_t);
                Offset              = Len * Index;
                if (Len !=
                    UI_NV_Write_Req(NV_SECTION_UI_CONTACTS_LIST, Offset, Len, (UINT8 *)(&NvContact)))
                {
                    /* error */
                    return(1);
                }

                /* update the description for Contacts interface */
                if (NULL != Nav_Get_Param(ACT_ID_CONTACTS)) // Contacts interface in the stack
                {
                    g_ContactsMng.InterfaceCtrl.FocusContact =
                        g_ContactsMng.InterfaceCtrl.Focus;
                    g_ContactsMng.InterfaceCtrl.Focus = NULL;
                    Contacts_Update_Contacts_Interface();
                }

                Contacts_Create_Contacts_Saved(PHONE_TEXT_ID_REPLACED);
            }
            else
            {
                g_ContactsMng.ContactOper.Action = CONTACTS_ACTION_REPLACE_PHASE_1;

                Contacts_Send_Write_Phonebook_Req(g_ContactsMng.ContactOper.DestMemory,
                                                  NULL, NULL,
                                                  Index);
            }
            break;

        default:
            break;
        } /* switch */
    }

    return(1);
} /* Contacts_Replace_Key_Cb */

/**
 * Create Contacts_Replace interface
 * param (in) VOID
 * return  VOID
 */
VOID Contacts_Create_Contacts_Replace(VOID)
{
    UI_Normal_NoTitle_Desc_t *Interface;
    Nav_Func_List_t          FuncList;

    Interface = (UI_Normal_NoTitle_Desc_t *)Hal_Mem_Alloc(sizeof(UI_Normal_NoTitle_Desc_t));
    Hal_Mem_Set(Interface, 0, sizeof(UI_Normal_NoTitle_Desc_t));

    g_ContactsMng.InterfaceCtrl.InterfaceId = ACT_ID_CONTACTS_REPLACE;
    g_ContactsMng.InterfaceCtrl.Ctrl        = (VOID *)Interface;

    Interface->ContenCont.ContLabel.TxtId      = LV_LANG_TXT_ID_NONE;
    Interface->ContenCont.ContLabel.TxtAlign   = LV_LABEL_ALIGN_LEFT;
    Interface->ContenCont.ContLabel.LabelAlign = LV_ALIGN_IN_TOP_LEFT;
    Interface->ContenCont.ContLabelAlign       = LV_ALIGN_IN_TOP_LEFT;

    Interface->ButtonBar.ButtonL.Valid = FALSE;
    Interface->ButtonBar.ButtonM.Valid = TRUE;
    Interface->ButtonBar.ButtonM.TxtId = PHONE_TEXT_ID_OK;
    Interface->ButtonBar.ButtonR.Valid = TRUE;
    Interface->ButtonBar.ButtonR.TxtId = PHONE_TEXT_ID_BACK;

    Interface->KeyFunc = Contacts_Replace_Key_Cb;

    Hal_Mem_Set(&FuncList, 0, sizeof(Nav_Func_List_t));
    FuncList.OnShow         = UI_Normal_NoTitle_Create;
    FuncList.OnCreate       = Contacts_Replace_OnCreate;
    FuncList.OnRestoreState = Contacts_Replace_OnRestoreState;
    FuncList.OnDestroy      = Contacts_Interface_OnDestroy;

    Nav_Forward(ACT_ID_ANY, ACT_ID_CONTACTS_REPLACE, &FuncList, g_ContactsMng.InterfaceCtrl.Ctrl);
}

/**
 * Create Contacts_Saved interface
 * param (in) TxtId: UINT16
 * return  VOID
 */
VOID Contacts_Create_Contacts_Saved(UINT16 TxtId)
{
    UI_Status_Desc_t *StatusDesc;
    Nav_Func_List_t  FuncList;
    ACTIVITY_ID      SrcActId = g_ContactsMng.InterfaceCtrl.SrcActId;

    UI_Log_Out(UI_SUB_MODULE_FRAMEWORK, UI_LOG_LEVEL_TRACE_2, "Contacts_Create_Contacts_Saved, SrcActId %d\n", SrcActId);

    StatusDesc = (UI_Status_Desc_t *)Hal_Mem_Alloc(sizeof(UI_Status_Desc_t));
    Hal_Mem_Set(StatusDesc, 0, sizeof(UI_Status_Desc_t));

    g_ContactsMng.InterfaceCtrl.InterfaceId = ACT_ID_CONTACTS_SAVED;
    g_ContactsMng.InterfaceCtrl.Ctrl        = (VOID *)StatusDesc;

    StatusDesc->ContLabel.TxtId      = TxtId;
    StatusDesc->ContLabel.TxtAlign   = LV_LABEL_ALIGN_LEFT;
    StatusDesc->ContLabel.LabelAlign = LV_ALIGN_IN_TOP_LEFT;
    StatusDesc->ContLabelAlign       = LV_ALIGN_IN_TOP_LEFT;

    StatusDesc->ContImg.Img  = SYMBOL_CHECKED;
    StatusDesc->ContImgAlign = LV_ALIGN_IN_TOP_RIGHT;

    StatusDesc->KeyFunc = Contacts_Status_Interface_Key_Cb;

    Hal_Mem_Set(&FuncList, 0, sizeof(Nav_Func_List_t));
    FuncList.OnShow    = UI_Status_Create;
    FuncList.OnCreate  = Contacts_Status_Interface_OnCreate;
    FuncList.OnDestroy = Contacts_Interface_OnDestroy;

    Nav_Backward_And_Forward(ACT_ID_ANY, SrcActId, ACT_ID_CONTACTS_SAVED, &FuncList, g_ContactsMng.InterfaceCtrl.Ctrl);
} /* Contacts_Create_Contacts_Saved */

/**
 * Create Contacts_Add_Warning interface
 * param (in) VOID
 * return  VOID
 */
VOID Contacts_Create_Add_Warning(VOID)
{
    UI_Status_Desc_t *StatusDesc;
    Nav_Func_List_t  FuncList;

    StatusDesc = (UI_Status_Desc_t *)Hal_Mem_Alloc(sizeof(UI_Status_Desc_t));
    Hal_Mem_Set(StatusDesc, 0, sizeof(UI_Status_Desc_t));

    g_ContactsMng.InterfaceCtrl.InterfaceId = ACT_ID_CONTACTS_ADD_WARNING;
    g_ContactsMng.InterfaceCtrl.Ctrl        = (VOID *)StatusDesc;

    StatusDesc->ContLabel.TxtId      = PHONE_TEXT_ID_NO_NAME_NUMBER;
    StatusDesc->ContLabel.TxtAlign   = LV_LABEL_ALIGN_LEFT;
    StatusDesc->ContLabel.LabelAlign = LV_ALIGN_IN_TOP_LEFT;
    StatusDesc->ContLabelAlign       = LV_ALIGN_IN_TOP_LEFT;

    StatusDesc->ContImg.Img  = LV_SYMBOL_WARNING;
    StatusDesc->ContImgAlign = LV_ALIGN_IN_TOP_RIGHT;

    StatusDesc->KeyFunc = Contacts_Status_Interface_Key_Cb;

    Hal_Mem_Set(&FuncList, 0, sizeof(Nav_Func_List_t));
    FuncList.OnShow    = UI_Status_Create;
    FuncList.OnCreate  = Contacts_Status_Interface_OnCreate;
    FuncList.OnDestroy = Contacts_Interface_OnDestroy;

    Nav_Forward(ACT_ID_ANY, ACT_ID_CONTACTS_ADD_WARNING, &FuncList, g_ContactsMng.InterfaceCtrl.Ctrl);
}

/**
 * Callback function for handling key pressed on Contacts_Add interface
 * param (in) Obj: lv_obj_t *
 * param (in) Key_Sta: UI_KEY_STATUS
 * param (in) Key_Val: UI_KEY_VALUE
 * return  UINT8
 */
UINT8 Contacts_Add_Key_Cb(lv_obj_t *Obj, UI_KEY_STATUS Key_Sta, UI_KEY_VALUE Key_Val)
{
    UINT8                           Ret        = 1;
    UI_Normal_Container_List_Desc_t *Interface =
        (UI_Normal_Container_List_Desc_t *)g_ContactsMng.InterfaceCtrl.Ctrl;
    UI_Container_Base_Desc_t        *ContList = Interface->ContList.ContainerList;
    lv_obj_t                        *Ta       = ContList[Interface->ContList.Index].u.Ta.TextArea;
    INT8                            Char      = 0;
    const INT8                      *Name;
    const INT8                      *Number;
    UINT8                           Len;
    Contacts_Info_t                 *ContactInfo;
    UINT8                           NameLen;
    UINT8                           NumberLen;

    if (KEY_RELEASED == Key_Sta)
    {
        switch (Key_Val)
        {
        case KEY_SOFTLEFT: // back
            Nav_Back(ACT_ID_ANY);
            break;

        case KEY_SOFTRIGHT: // clear
            lv_textarea_del_char(Ta);
            break;

        case KEY_0:
        case KEY_1:
        case KEY_2:
        case KEY_3:
        case KEY_4:
        case KEY_5:
        case KEY_6:
        case KEY_7:
        case KEY_8:
        case KEY_9:
        case KEY_ASTERISK:
        case KEY_HASH:
            if (KEY_ASTERISK == Key_Val)
            {
                Char = '*';
            }
            else if (KEY_HASH == Key_Val)
            {
                Char = '#';
            }
            else
            {
                Char = Key_Val - KEY_0 + '0';
            }
            lv_textarea_add_char(Ta, Char);
            if (0 == Interface->ContList.Index)
            {
                Contacts_Input_Handler(0);
                break;
            }
            break;

        case KEY_UP:
        case KEY_DOWN:
            if (CONTACTS_ACTION_ADD_REQ == g_ContactsMng.ContactOper.Action)
            {   /* add number from other module, not modify phone number */
                break;
            }

            lv_textarea_set_cursor_hidden(Ta, FALSE);

            if (0 == Interface->ContList.Index)
            {
                Interface->ButtonBar.ButtonL.ButtonIndex = Ime_Get_Mode();
            }

            if (KEY_UP == Key_Val)
            {
                if (0 == Interface->ContList.Index)
                {
                    Interface->ContList.Index = Interface->ContList.ListContainerCnt - 1;
                }
                else
                {
                    Interface->ContList.Index--;
                }
            }
            else
            {
                if ((Interface->ContList.ListContainerCnt - 1) == Interface->ContList.Index)
                {
                    Interface->ContList.Index = 0;
                }
                else
                {
                    Interface->ContList.Index++;
                }
            }

            if (0 == Interface->ContList.Index)
            {
                Ime_Set_SingleMode(FALSE);
                Ime_Set_Mode(Interface->ButtonBar.ButtonL.ButtonIndex);
            }
            else if (1 == Interface->ContList.Index)
            {
                Ime_Set_Mode(LV_IME_MODE_NUM);
                Ime_Set_SingleMode(TRUE);
            }

            Ta = ContList[Interface->ContList.Index].u.Ta.TextArea;
            lv_textarea_set_cursor_hidden(Ta, FALSE);

            Ret = 0;
            break;

        case KEY_LEFT:
            lv_textarea_cursor_left(Ta);
            break;

        case KEY_RIGHT:
            lv_textarea_cursor_right(Ta);
            break;

        case KEY_OK: // Save
            /* get contact name */
            Ta      = ContList[0].u.Ta.TextArea;
            Name    = lv_textarea_get_text(Ta);
            NameLen = strlen(Name);
            if (0 == NameLen) // no name
            {
                Contacts_Create_Add_Warning();
                break;
            }

            Ta        = ContList[1].u.Ta.TextArea;
            Number    = lv_textarea_get_text(Ta);
            NumberLen = strlen(Number);
            if (0 == NumberLen) // no number
            {
                Contacts_Create_Add_Warning();
                break;
            }

            ContactInfo = (Contacts_Info_t *)Hal_Mem_Alloc(sizeof(Contacts_Info_t));
            Hal_Mem_Set(ContactInfo, 0, sizeof(Contacts_Info_t));
            Hal_Mem_Copy(ContactInfo->Name, (INT8 *)Name, NameLen);
            Hal_Mem_Copy(ContactInfo->Number, (INT8 *)Number, NumberLen);
            ContactInfo->ToneIndex = IF_CONTACTS_DEFAULT_TONE;
            ContactInfo->MemoryAndIndex
                = Contacts_Set_Contact_Memory(g_ContactsMng.ContactOper.DestMemory);

            g_ContactsMng.InterfaceCtrl.Focus = NULL;
            if (0 == Contacts_Add_Contact(ContactInfo, NULL, &g_ContactsMng.InterfaceCtrl.Focus))
            {   /* name repetition */
                if (CONTACTS_ACTION_ADD == g_ContactsMng.ContactOper.Action)
                {
                    if (NULL != g_ContactsMng.InterfaceCtrl.Number)
                    {
                        /* error */
                    }

                    Len                                = NumberLen + 1;
                    g_ContactsMng.InterfaceCtrl.Number = (INT8 *)Hal_Mem_Alloc(Len);
                    Hal_Mem_Copy(g_ContactsMng.InterfaceCtrl.Number, (INT8 *)Number, Len);
                }

                Contacts_Create_Contacts_Replace();
                break;
            }

            g_ContactsMng.PhkStatus[g_ContactsMng.ContactOper.DestMemory].Used++;
            if (CONTACTS_MEMORY_PHONE == g_ContactsMng.ContactOper.DestMemory)
            {
                Contacts_Add_Contact_To_Nvm(ContactInfo);

                /* update the description for Contacts interface */
                if (CONTACTS_ACTION_ADD_REQ != g_ContactsMng.ContactOper.Action)
                {
                    g_ContactsMng.InterfaceCtrl.FocusContact =
                        g_ContactsMng.InterfaceCtrl.Focus;
                    g_ContactsMng.InterfaceCtrl.Focus = NULL;
                    Contacts_Update_Contacts_Interface();
                }

                Contacts_Create_Contacts_Saved(PHONE_TEXT_ID_CONTACT_SAVED_PHONE);
            }
            else
            {
                Contacts_Send_Write_Phonebook_Req(g_ContactsMng.ContactOper.DestMemory,
                                                  ContactInfo->Name, ContactInfo->Number,
                                                  MMI_MODEM_CONTACT_INDEX_INVALID);
            }
            break;

        case KEY_END:
            Nav_Home(ACT_ID_ANY);
            break;

        default:
            break;
        } /* switch */
    }

    return(Ret);
} /* Contacts_Add_Key_Cb */

/**
 * Process UI input char number event
 * param (in) Len: UINT8. 0 means backspace
 * return  void
 */
VOID Contacts_Input_Handler(UINT8 Len)
{
    UI_Normal_Container_List_Desc_t *If = (UI_Normal_Container_List_Desc_t *)g_ContactsMng.InterfaceCtrl.Ctrl;
    lv_obj_t                        *Ta = If->ContList.ContainerList[0].u.Ta.TextArea; /*contact name*/
    const char                      *Text = lv_textarea_get_text(Ta);
    UINT8                           TxtLen = strlen(Text);
    UINT8                           i = 0;
    UINT8                           NonChineseCharsNum = 0;
    UINT8                           ChineseCharsNum = 0;
    UINT8                           Offset;
    char                            *NewTxt = NULL;

    if (CONTACTS_MEMORY_PHONE == g_ContactsMng.ContactOper.DestMemory)
    {
        return;
    }

    if (0 != If->ContList.Index)
    {
        return;
    }

    if (CONTACTS_SIM_NAME_MAX_CHAR_NUM_WITH_CHINESE >= TxtLen)
    {
        return;
    }

    while ('\0' != Text[i])
    {
        if (0 == (Text[i] & 0x80)) /*ASCII*/
        {
            NonChineseCharsNum++;
            Offset = 1;
        }
        else
        {
            if (0xC0 == (Text[i] & 0xE0)) /*2 bytes UTF-8 code*/
            {
                ChineseCharsNum++;
                Offset = 2;
            }
            else if (0xE0 == (Text[i] & 0xF0)) /*3 bytes UTF-8 code*/
            {
                ChineseCharsNum++;
                Offset = 3;
            }
            else if (0xF0 == (Text[i] & 0xF8)) /*4 bytes UTF-8 code*/
            {
                ChineseCharsNum++;
                Offset = 4;
            }
            else /*Not UTF-8 char. Go the next*/
            {
                NonChineseCharsNum++;
                Offset = 1;
            }
        }
        if (0 == ChineseCharsNum)
        {
            if (CONTACTS_SIM_NAME_MAX_CHAR_NUM_WITHOUT_CHINESE < NonChineseCharsNum)
            {
                NewTxt = (char *)Hal_Mem_Alloc(i + 1);
                snprintf(NewTxt, i + 1, "%s", Text);
                break;
            }
        }
        else
        {
            if (CONTACTS_SIM_NAME_MAX_CHAR_NUM_WITH_CHINESE < (NonChineseCharsNum + ChineseCharsNum))
            {
                NewTxt = (char *)Hal_Mem_Alloc(i + 1);
                snprintf(NewTxt, i + 1, "%s", Text);
                break;
            }
        }

        i += Offset;
    }

    if (NewTxt)
    {
        lv_textarea_set_text(Ta, NewTxt);
        Hal_Mem_Free(NewTxt);
    }
}

/**
 * Callback function for additional actions after Creating Contacts_Add interface
 * param (in) Ctrl: VOID *
 * return  VOID
 */
VOID Contacts_Add_OnCreate(VOID *Ctrl)
{
    UI_Normal_Container_List_Desc_t *Interface = (UI_Normal_Container_List_Desc_t *)Ctrl;
    UI_Container_Base_Desc_t        *ContList  = Interface->ContList.ContainerList;
    lv_obj_t                        *Ta;

    Ta = ContList[0].u.Ta.TextArea;
    if (CONTACTS_MEMORY_PHONE == g_ContactsMng.ContactOper.DestMemory)
    {
        lv_textarea_set_max_length(Ta, CONTACTS_MAX_NAME_LENGTH - 1);
    }
    else
    {
        /*dynamically calculate the maximum length of text on TA
         *after input or delete for SIM1 or SIM2*/
        lv_textarea_set_max_length(Ta, 0);
        Ime_Set_GetCharLen_Func(Contacts_Input_Handler);
    }
    Ime_Set_SingleMode(FALSE);

    Ta = ContList[1].u.Ta.TextArea;
    lv_textarea_set_max_length(Ta, CONTACTS_MAX_NUMBER_LENGTH - 1);
}

/**
 * Callback function for saving state on Contacts_Add interface before forward to another activity
 * param (in) Ctrl: VOID *
 * return  VOID
 */
VOID Contacts_Add_OnSaveState(VOID *Ctrl)
{
    UI_Normal_Container_List_Desc_t *Interface = (UI_Normal_Container_List_Desc_t *)Ctrl;
    UI_Container_Base_Desc_t        *ContList  = Interface->ContList.ContainerList;
    lv_obj_t                        *Ta;
    const INT8                      *Text;
    UINT8                           Len;

    Ta   = ContList[0].u.Ta.TextArea;
    Text = lv_textarea_get_text(Ta);
    if (0 != strlen(ContList[0].u.Ta.TaTxt))
    {
        Hal_Mem_Free(ContList[0].u.Ta.TaTxt);
        ContList[0].u.Ta.TaTxt = NULL;
    }
    Len = strlen(Text);
    if (0 != Len)
    {
        Len++;
        ContList[0].u.Ta.TaTxt = (INT8 *)Hal_Mem_Alloc(Len);
        Hal_Mem_Copy(ContList[0].u.Ta.TaTxt, (INT8 *)Text, Len);
    }
    else
    {
        ContList[0].u.Ta.TaTxt = "";
    }

    Ta   = ContList[1].u.Ta.TextArea;
    Text = lv_textarea_get_text(Ta);
    if (0 != strlen(ContList[1].u.Ta.TaTxt))
    {
        Hal_Mem_Free(ContList[1].u.Ta.TaTxt);
        ContList[1].u.Ta.TaTxt = NULL;
    }
    Len = strlen(Text);
    if (0 != Len)
    {
        Len++;
        ContList[1].u.Ta.TaTxt = (INT8 *)Hal_Mem_Alloc(Len);
        Hal_Mem_Copy(ContList[1].u.Ta.TaTxt, (INT8 *)Text, Len);
    }
    else
    {
        ContList[1].u.Ta.TaTxt = "";
    }

    if (0 == Interface->ContList.Index)
    {
        Interface->ButtonBar.ButtonL.ButtonIndex = Ime_Get_Mode();
    }
} /* Contacts_Add_OnSaveState */

/**
 * Callback function for restoring state on Contacts_Add interface after backward from another activity
 * param (in) Ctrl: VOID *
 * return  VOID
 */
VOID Contacts_Add_OnRestoreState(VOID *Ctrl)
{
    UI_Normal_Container_List_Desc_t *Interface = (UI_Normal_Container_List_Desc_t *)Ctrl;
    UI_Container_Base_Desc_t        *ContList  = Interface->ContList.ContainerList;
    lv_obj_t                        *Ta;

    g_ContactsMng.InterfaceCtrl.Ctrl        = Ctrl;
    g_ContactsMng.InterfaceCtrl.InterfaceId = ACT_ID_CONTACTS_ADD;

    Ta = ContList[0].u.Ta.TextArea;
    if (CONTACTS_MEMORY_PHONE == g_ContactsMng.ContactOper.DestMemory)
    {
        lv_textarea_set_max_length(Ta, CONTACTS_MAX_NAME_LENGTH - 1);
    }
    else
    {
        /*dynamically calculate the maximum length of text on TA
         *after input or delete for SIM1 or SIM2*/
        lv_textarea_set_max_length(Ta, 0);
        Ime_Set_GetCharLen_Func(Contacts_Input_Handler);
    }
    if (0 != Interface->ContList.Index)
    {
        lv_textarea_set_cursor_hidden(Ta, TRUE);
    }
    else
    {
        Ime_Set_SingleMode(FALSE);
    }

    Ta = ContList[1].u.Ta.TextArea;
    lv_textarea_set_max_length(Ta, CONTACTS_MAX_NUMBER_LENGTH - 1);
    if (1 == Interface->ContList.Index)
    {
        Ime_Set_Mode(LV_IME_MODE_NUM);
        Ime_Set_SingleMode(TRUE);
        lv_textarea_set_cursor_hidden(Ta, FALSE);
    }
}

/**
 * Callback function for destroying Contacts_Add interface which will be popped from stack
 * param (in) Ctrl: VOID *
 * return  VOID
 */
VOID Contacts_Add_OnDestroy(VOID *Ctrl)
{
    UI_Normal_Container_List_Desc_t *Interface = (UI_Normal_Container_List_Desc_t *)Ctrl;
    UI_Container_Base_Desc_t        *ContList  = Interface->ContList.ContainerList;

    if (0 != strlen(ContList[0].u.Ta.TaTxt))
    {
        Hal_Mem_Free(ContList[0].u.Ta.TaTxt);
    }
    if (0 != strlen(ContList[1].u.Ta.TaTxt))
    {
        Hal_Mem_Free(ContList[1].u.Ta.TaTxt);
    }
    Hal_Mem_Free(Interface->ContList.ContainerList);
    Hal_Mem_Free(Ctrl);
}

/**
 * Create Contacts_Add interface
 * param (in) VOID
 * return  VOID
 */
VOID Contacts_Create_Contacts_Add(VOID)
{
    UI_Normal_Container_List_Desc_t *Interface;
    UI_Container_Base_Desc_t        *ContList;
    Nav_Func_List_t                 FuncList;
    UINT8                           Len;

    Interface =
        (UI_Normal_Container_List_Desc_t *)Hal_Mem_Alloc(sizeof(UI_Normal_Container_List_Desc_t));
    Hal_Mem_Set(Interface, 0, sizeof(UI_Normal_Container_List_Desc_t));

    g_ContactsMng.InterfaceCtrl.InterfaceId = ACT_ID_CONTACTS_ADD;
    g_ContactsMng.InterfaceCtrl.Ctrl        = (VOID *)Interface;

    Interface->TitleBar.TxtId      = PHONE_TEXT_ID_CONTACT;
    Interface->TitleBar.TxtAlign   = LV_LABEL_ALIGN_CENTER;
    Interface->TitleBar.LabelAlign = LV_ALIGN_IN_TOP_LEFT;

    Interface->ContList.ListContainerCnt = 2;
    Interface->ContList.ContainerList    =
        (UI_Container_Base_Desc_t *)Hal_Mem_Alloc(sizeof(UI_Container_Base_Desc_t) * Interface->ContList.ListContainerCnt);
    ContList = Interface->ContList.ContainerList;
    Hal_Mem_Set(ContList, 0, sizeof(UI_Container_Base_Desc_t) * Interface->ContList.ListContainerCnt);

    ContList[0].Valid             = TRUE;
    ContList[0].Label.TxtId       = PHONE_TEXT_ID_NAMES;
    ContList[0].Label.TxtAlign    = LV_LABEL_ALIGN_LEFT;
    ContList[0].Label.LabelAlign  = LV_ALIGN_IN_TOP_LEFT;
    ContList[0].Choise            = UI_BASE_OBJ_TA;
    ContList[0].u.Ta.TaCursorHide = FALSE;
    ContList[0].u.Ta.TaAlign      = LV_ALIGN_IN_BOTTOM_LEFT;
    ContList[0].u.Ta.TaTxt        = "";
    ContList[0].ReleaseFunc       = NULL;

    ContList[1].Valid             = TRUE;
    ContList[1].Label.TxtId       = PHONE_TEXT_ID_NUMBERS;
    ContList[1].Label.TxtAlign    = LV_LABEL_ALIGN_LEFT;
    ContList[1].Label.LabelAlign  = LV_ALIGN_IN_TOP_LEFT;
    ContList[1].Choise            = UI_BASE_OBJ_TA;
    ContList[1].u.Ta.TaCursorHide = TRUE;
    ContList[1].u.Ta.TaAlign      = LV_ALIGN_IN_BOTTOM_LEFT;
    ContList[1].ReleaseFunc       = NULL;
    if (CONTACTS_ACTION_ADD_REQ == g_ContactsMng.ContactOper.Action)
    {
        if (NULL == g_ContactsMng.InterfaceCtrl.Number)
        {
            /* error */
            return;
        }

        Len                    = strlen(g_ContactsMng.InterfaceCtrl.Number) + 1;
        ContList[1].u.Ta.TaTxt = (INT8 *)Hal_Mem_Alloc(Len);
        Hal_Mem_Copy(ContList[1].u.Ta.TaTxt, g_ContactsMng.InterfaceCtrl.Number, Len);
    }
    else
    {
        ContList[1].u.Ta.TaTxt = "";
    }

    Interface->ButtonBar.ButtonL.Valid = TRUE;
    Interface->ButtonBar.ButtonL.TxtId = PHONE_TEXT_ID_BACK;
    Interface->ButtonBar.ButtonM.Valid = TRUE;
    Interface->ButtonBar.ButtonM.TxtId = PHONE_TEXT_ID_SAVE;
    Interface->ButtonBar.ButtonR.Valid = TRUE;
    Interface->ButtonBar.ButtonR.TxtId = PHONE_TEXT_ID_CLEAR;

    Interface->KeyFunc = Contacts_Add_Key_Cb;

    Hal_Mem_Set(&FuncList, 0, sizeof(Nav_Func_List_t));
    FuncList.OnShow         = UI_Normal_Container_List_Create;
    FuncList.OnCreate       = Contacts_Add_OnCreate;
    FuncList.OnSaveState    = Contacts_Add_OnSaveState;
    FuncList.OnRestoreState = Contacts_Add_OnRestoreState;
    FuncList.OnDestroy      = Contacts_Add_OnDestroy;

    Nav_Forward(ACT_ID_ANY, ACT_ID_CONTACTS_ADD, &FuncList, g_ContactsMng.InterfaceCtrl.Ctrl);
} /* Contacts_Create_Contacts_Add */

/**
 * Action if pressing SIM1 button on Contacts_Add_Sel_Mem interface
 * param (in) lv_obj_t *Btn,lv_event_t event
 * return  void
 */
void Contacts_Add_Sel_Mem_Btn_Sim1_Cb(lv_obj_t *Btn,lv_event_t event)
{
    if(LV_EVENT_CLICKED != event)
    {
        return;
    }

    CONTACTS_MEMORY Memory = CONTACTS_MEMORY_SIM1;

    if (g_ContactsMng.PhkStatus[Memory].Used == g_ContactsMng.PhkStatus[Memory].Total)
    {
        Contacts_Create_Contacts_Full();
    }
    else
    {
        g_ContactsMng.ContactOper.DestMemory = Memory;
        Contacts_Create_Contacts_Add();
    }
}

/**
 * Action if pressing SIM2 button on Contacts_Add_Sel_Mem interface
 * param (in) lv_obj_t *Btn,lv_event_t event
 * return  void
 */
void Contacts_Add_Sel_Mem_Btn_Sim2_Cb(lv_obj_t *Btn,lv_event_t event)
{
    if(LV_EVENT_CLICKED != event)
    {
        return;
    }

    CONTACTS_MEMORY Memory = CONTACTS_MEMORY_SIM2;

    if (g_ContactsMng.PhkStatus[Memory].Used == g_ContactsMng.PhkStatus[Memory].Total)
    {
        Contacts_Create_Contacts_Full();
    }
    else
    {
        g_ContactsMng.ContactOper.DestMemory = Memory;
        Contacts_Create_Contacts_Add();
    }
}

/**
 * Action if pressing phone button on Contacts_Add_Sel_Mem interface
 * param (in) lv_obj_t *Btn,lv_event_t event
 * return  void
 */
void Contacts_Add_Sel_Mem_Btn_Phone_Cb(lv_obj_t *Btn,lv_event_t event)
{
    if(LV_EVENT_CLICKED != event)
    {
        return;
    }

    CONTACTS_MEMORY Memory = CONTACTS_MEMORY_PHONE;

    if (g_ContactsMng.PhkStatus[Memory].Used == g_ContactsMng.PhkStatus[Memory].Total)
    {
        Contacts_Create_Contacts_Full();
    }
    else
    {
        g_ContactsMng.ContactOper.DestMemory = Memory;
        Contacts_Create_Contacts_Add();
    }
}

/**
 * Public callback function for destroying Contacts_Add_Sel_Mem interface with List control which will be popped from stack
 * param (in) Ctrl: VOID *
 * return  VOID
 */
VOID Contacts_Add_Sel_Mem_OnDestroy(VOID *Ctrl)
{
    Hal_Mem_Free(((UI_Normal_List_Only_Desc_t *)Ctrl)->List.ButtonList);
    Hal_Mem_Free(Ctrl);
    if (NULL != g_ContactsMng.InterfaceCtrl.Number)
    {
        Hal_Mem_Free(g_ContactsMng.InterfaceCtrl.Number);
        g_ContactsMng.InterfaceCtrl.Number = NULL;
    }
    g_ContactsMng.ContactOper.Action = CONTACTS_ACTION_NULL;
}

/**
 * Callback function for restoring the interface with List control which will be popped from stack
 * param (in) Ctrl: VOID *
 * return  VOID
 */
VOID Contacts_Add_Sel_Mem_OnRestoreState(VOID *Ctrl)
{
    g_ContactsMng.InterfaceCtrl.Ctrl        = Ctrl;
    g_ContactsMng.InterfaceCtrl.InterfaceId = ACT_ID_CONTACTS_ADD_SEL_MEM;
}

/**
 * Create Contacts_Add_Sel_Mem interface
 * param (in) VOID
 * return  VOID
 */
VOID Contacts_Create_Contacts_Add_Sel_Mem(VOID)
{
    UI_Normal_List_Only_Desc_t *NormalLstOnlyDesc;
    Nav_Func_List_t            FuncList;
    UINT8                      i = 0;
    UINT32                     Len;

    NormalLstOnlyDesc =
        (UI_Normal_List_Only_Desc_t *)Hal_Mem_Alloc(sizeof(UI_Normal_List_Only_Desc_t));
    Hal_Mem_Set(NormalLstOnlyDesc, 0, sizeof(UI_Normal_List_Only_Desc_t));

    g_ContactsMng.InterfaceCtrl.InterfaceId = ACT_ID_CONTACTS_ADD_SEL_MEM;
    g_ContactsMng.InterfaceCtrl.Ctrl        = (VOID *)NormalLstOnlyDesc;

    NormalLstOnlyDesc->TitleBar.TxtId      = PHONE_TEXT_ID_SEL_CONTMEM;
    NormalLstOnlyDesc->TitleBar.TxtAlign   = LV_LABEL_ALIGN_CENTER;
    NormalLstOnlyDesc->TitleBar.LabelAlign = LV_ALIGN_IN_TOP_LEFT;

    NormalLstOnlyDesc->List.ListButtonCnt = 1;
    if (CONTACTS_PHONEBOOK_STATUS_READ_DONE == g_ContactsMng.PhonebookStatus[0])
    {
        NormalLstOnlyDesc->List.ListButtonCnt++;
    }
    if (CONTACTS_PHONEBOOK_STATUS_READ_DONE == g_ContactsMng.PhonebookStatus[1])
    {
        NormalLstOnlyDesc->List.ListButtonCnt++;
    }
    Len = sizeof(UI_Button_Desc_t) *
          NormalLstOnlyDesc->List.ListButtonCnt;
    NormalLstOnlyDesc->List.ButtonList = (UI_Button_Desc_t *)Hal_Mem_Alloc(Len);
    Hal_Mem_Set(NormalLstOnlyDesc->List.ButtonList, 0, Len);

    NormalLstOnlyDesc->List.ButtonList[i].Valid        = TRUE;
    NormalLstOnlyDesc->List.ButtonList[i].ButtonIndex  = i;
    NormalLstOnlyDesc->List.ButtonList[i].TxtId        = PHONE_TEXT_ID_PHONE;
    NormalLstOnlyDesc->List.ButtonList[i++].ReleaseFun = Contacts_Add_Sel_Mem_Btn_Phone_Cb;

    if (CONTACTS_PHONEBOOK_STATUS_READ_DONE == g_ContactsMng.PhonebookStatus[0])
    {
        NormalLstOnlyDesc->List.ButtonList[i].Valid        = TRUE;
        NormalLstOnlyDesc->List.ButtonList[i].ButtonIndex  = i;
        NormalLstOnlyDesc->List.ButtonList[i].TxtId        = PHONE_TEXT_ID_SIM1;
        NormalLstOnlyDesc->List.ButtonList[i++].ReleaseFun = Contacts_Add_Sel_Mem_Btn_Sim1_Cb;
    }

    if (CONTACTS_PHONEBOOK_STATUS_READ_DONE == g_ContactsMng.PhonebookStatus[1])
    {
        NormalLstOnlyDesc->List.ButtonList[i].Valid        = TRUE;
        NormalLstOnlyDesc->List.ButtonList[i].ButtonIndex  = i;
        NormalLstOnlyDesc->List.ButtonList[i].TxtId        = PHONE_TEXT_ID_SIM2;
        NormalLstOnlyDesc->List.ButtonList[i++].ReleaseFun = Contacts_Add_Sel_Mem_Btn_Sim2_Cb;
    }

    NormalLstOnlyDesc->BtnBar.ButtonL.Valid = FALSE;
    NormalLstOnlyDesc->BtnBar.ButtonM.Valid = TRUE;
    NormalLstOnlyDesc->BtnBar.ButtonM.TxtId = PHONE_TEXT_ID_SELECT;
    NormalLstOnlyDesc->BtnBar.ButtonR.Valid = TRUE;
    NormalLstOnlyDesc->BtnBar.ButtonR.TxtId = PHONE_TEXT_ID_BACK;

    NormalLstOnlyDesc->KeyFunc = Contacts_Normal_List_Interface_Key_Cb;

    Hal_Mem_Set(&FuncList, 0, sizeof(Nav_Func_List_t));
    FuncList.OnShow         = UI_Normal_List_Only_Create;
    FuncList.OnRestoreState = Contacts_Add_Sel_Mem_OnRestoreState;
    FuncList.OnDestroy      = Contacts_Add_Sel_Mem_OnDestroy;

    Nav_Forward(ACT_ID_ANY, ACT_ID_CONTACTS_ADD_SEL_MEM, &FuncList, g_ContactsMng.InterfaceCtrl.Ctrl);
} /* Contacts_Create_Contacts_Add_Sel_Mem */

/**
 * Save phone number to contact
 * param (in) SrcActId: UINT16, refers to ACTIVITY_ID in nav.h
 * param (in) Number: INT8 *
 * return  VOID
 */
VOID Contacts_Save_Contact_Req(UINT16 SrcActId, INT8 *Number)
{
    if (NULL == Number)
    {
        /* error */
        return;
    }

    if (NULL != g_ContactsMng.InterfaceCtrl.Number)
    {
        /* error */
        return;
    }

    g_ContactsMng.ContactOper.Action     = CONTACTS_ACTION_ADD_REQ;
    g_ContactsMng.InterfaceCtrl.Number   = Number;
    g_ContactsMng.InterfaceCtrl.SrcActId = SrcActId;
    Contacts_Create_Contacts_Add_Sel_Mem();
}
